# coding: utf-8
import json
import logging
from collections import defaultdict
from datetime import datetime
from typing import Dict, List

import pandas as pd
import redis

from qp_base.options import get_option as get_common_option

logger = logging.getLogger(__name__)


class Ctx:
    """connection context"""

    def __init__(self):
        self._redis_cli = None
        self._ticks: Dict[str, List[Dict]] = defaultdict(list)

    @property
    def redis_cli(self):
        """redis live quote data storage"""
        if not self._redis_cli:
            redis_url = get_common_option(
                "qoute_redis_server", "redis://:123456:localhost:6379"
            )
            redis_url = 'redis://127.0.0.1:6379'
            self._redis_cli = redis.from_url(redis_url)
        return self._redis_cli


ctx = Ctx()


def resample_tick21m(symbol, tick_df):
    if tick_df.empty:
        return None

    res = tick_df.resample("T", label="right")
    bar_df = pd.DataFrame(
        {
            "open": res["current"].first().fillna(method="ffill"),
            "close": res["current"].last().fillna(method="ffill"),
            "high": res["current"].max().fillna(method="ffill"),
            "low": res["current"].min().fillna(method="ffill"),
            "volume": (res["day_volume"].last() - res["day_volume"].first()).fillna(
                0.0
            ),
            "money": (res["day_amount"].last() - res["day_amount"].first()).fillna(0.0),
            "pre_close": res["pre_close"].first().fillna(method="ffill"),
            "pre_settle": res["pre_settle"].first().fillna(method="ffill"),
            "high_limit": res["limit_up"].first().fillna(method="ffill"),
            "low_limit": res["limit_down"].first().fillna(method="ffill"),
            "pe_ratio1": res["pe_ratio1"].last().fillna(method="ffill"),
            "pe_ratio2": res["pe_ratio2"].last().fillna(method="ffill"),
            "is_st": 0,  # TODO
            "paused": 0,  # 有行情都没有停牌
            "symbol": symbol,
        }
    )
    bar_df["avg"] = (bar_df["money"] / bar_df["volume"]).fillna(method="ffill")
    bar_df["dt"] = bar_df.index
    return bar_df


def get_today_bars(symbol: str, inclue_now: bool = True):
    """获取当日该标的的所有 bar，支持分钟和天

    :param symbol: 标的代码
    :param freq: bar 频率，1m/1d
    :param inclue_now: 分钟频率时，是否包含当前不完整的 bar
    """
    tick_df = get_today_ticks(symbol)
    if not inclue_now:
        curr_min = datetime.now().replace(second=0, microsecond=0)
        tick_df = tick_df[tick_df.index < curr_min]
    return resample_tick21m(symbol, tick_df)


def get_today_ticks(symbol):
    """获取当日该标的的所有 tick

    :param symbol: 标的代码
    """
    local_tick_cnt = len(ctx._ticks[symbol])
    try:
        ticks = ctx.redis_cli.lrange(f"tick_quotes.{symbol}", local_tick_cnt, -1)
    except KeyError:
        return None
    for tick_str in ticks:
        ctx._ticks[symbol].append(json.loads(tick_str))
    tick_df = pd.DataFrame(ctx._ticks[symbol])
    if not tick_df.empty:
        tick_df["dt"] = tick_df["dt"].apply(lambda s: datetime.fromtimestamp(s))
        tick_df["recv_ts"] = tick_df["recv_ts"].apply(
            lambda s: datetime.fromtimestamp(s)
        )
        return tick_df.set_index("dt").sort_index()
    return tick_df


def get_current_bar(symbol, force_now=False):
    """获取当前 bar 数据

    :param symbol: 标的代码
    :param force_now: 强制返回当前分钟的 bar，如果当前分钟没有 tick 数据，返回 None
    """
    tick_df = get_today_ticks(symbol)
    if force_now:
        curr_min = datetime.now().replace(second=0, microsecond=0)
    else:
        curr_min = tick_df.index[-1].replace(second=0, microsecond=0)
    tick_df = tick_df[tick_df.index >= curr_min]
    tick_df = tick_df[-1:]
    return resample_tick21m(symbol, tick_df)


def get_current_tick(symbol):
    """获取最新一个 tick 数据"""
    # try:
    tick_data = ctx.redis_cli.lrange(f"tick_quotes.{symbol}", -1, -1)
    if tick_data:
        return json.loads(tick_data[0])
    # except Exception:
    #     logger.exception("get_current_tick[%s] exception: ", symbol)
    #     return None

res=get_current_tick('000001.XSHE')
print(res)
res=get_today_ticks('000001.XSHE')
print(res)
res= get_current_bar('000001.XSHE')
print(res)
res= get_today_bars('000001.XSHE')
print(res)
